import 'dart:collection';

import 'package:dio/dio.dart';
import 'package:sp_util/sp_util.dart';

import 'package:booksea/core/services/cache.dart';

class CacheObject {
  CacheObject(this.response)
  : timeStamp = DateTime.now().millisecondsSinceEpoch;
  Response response;
  int timeStamp;

  @override
  bool operator ==(Object other) {
    return response.hashCode == other.hashCode;
  }

  @override
  // TODO: implement hashCode
  int get hashCode => response.realUri.hashCode;
}

class NetCacheInterceptor extends Interceptor {
  //为确保迭代器顺序和对象插入时间一致顺序一致，我们使用LinkedHashMap
  var cache = LinkedHashMap<String, CacheObject>();

  @override
  Future onRequest(RequestOptions options) async {
    // 不缓存
    if(!CACHE_ENABLE) return options;

    // refresh标记是否是刷新缓存
    bool refresh = options.extra["refresh"] == true;

    // 是否磁盘缓存
    bool cacheDisk = options.extra["cacheDisk"] == true;

    //如果刷新,先删除相关缓存
    if(refresh) {
      //删除uri相同的内存缓存
      delete(options.uri.toString());

      //删除磁盘缓存
      if(cacheDisk) {
        await SpUtil.remove(options.uri.toString());
      }
      return options;
    }

    // get请求,开启缓存
    if(options.extra["noCache"] != true && options.method.toLowerCase() == 'get') {
      String key = options.extra['cacheKey'] ?? options.uri.toString();

      // 策略 1.内存缓存优先 2.然后才是磁盘缓存
      //1.内存缓存
      var ob = cache[key];
      if(ob != null){
        //若缓存未过期,则返回缓存内容
        if((DateTime.now().millisecondsSinceEpoch - ob.timeStamp) / 1000 < CACHE_MAXAGE){
          return cache[key].response;
        } else {
          //若已过期则删除缓存,继续向服务器请求
          cache.remove(key);
        }
      }

      //2.磁盘缓存
      if(cacheDisk) {
        var cacheData = SpUtil.getObject(key);
        if(cacheData != null) {
          return Response(
            statusCode: 200,
            data: cacheData
          );
        }
      }
    }
  }

  @override
  Future onError(DioError err) async {
    // 错误状态不缓存
  }

  @override
  Future onResponse(Response response) async {
    // 如果启用缓存,将返回结果保存到缓存
    if(CACHE_ENABLE) {
      await _saveCache(response);
    }
  }

  Future<void> _saveCache(Response object) async {
    RequestOptions options = object.request;
    // 只缓存get的请求
    if(options.extra['noCache'] != true && options.method.toLowerCase() == "get") {
      // 策略: 内存、磁盘都写缓存

      // 缓存key
      String key = options.extra["cacheKey"] ?? options.uri.toString();

      // 磁盘缓存
      if(options.extra["cacheDisk"] == true) {
        await SpUtil.putObject(key, object.data);
      }

      //内存缓存,如果缓存数量超过最大数量限制，则先移除最早的一条记录
      if(cache.length == CACHE_MAXCOUNT) {
        cache.remove(cache[cache.keys.first]);
      }
      cache[key] = CacheObject(object);
    }
  }

  void delete(String key) {
    cache.remove(key);
  }
}